//
//  "$Id: Storage.h 28913 2011-06-30 09:45:22Z wang_haifeng $"
//
//  Copyright (c)1992-2010, ZheJiang Dahua Technology Stock CO.LTD.
//  All Rights Reserved.
//
//	Description:
//	Revisions:		Year-Month-Day  SVN-Author  Modification
//

#ifndef __STORAGE_API_H__
#define __STORAGE_API_H__

#include "Types.h"
#include "Defs.h"

#ifdef __cplusplus
extern "C" {
#endif

/// \defgroup StorageAPI API Storage
/// 存储设备接口。
/// @{

/// 分区状态信息
typedef enum PartitionStatus 
{
	partitionLvAvailable = 0, ///< LV可用状态
	partitionLvNotAvailable = 1, ///< LV不可用状态
} PartitionStatus;


/// 存储设备分区信息, 128字节
typedef struct
{
	char	name[32];		///< 分区名，"/dev/sda1", "/dev/hda1", "/dev/idea1"...
	char	fs[16];			///< 文件系统类型，"DHFS", "EXT3", "EXT4", "XFS", "VFAT", "TAEFS"... ""表示还没有格式化
	uint64	start;			///< 开始偏移，字节为单位
	uint64	total;			///< 总大小，字节为单位
	PartitionStatus	status:8; ///< 分区状态，LV在使用
	int		placeholder:24;	///< 按四字节对齐的占位符
	int		reserved[15];	///< 保留空间
} StoragePartitionInfo;


/// 存储设备详细信息, 256字节
typedef struct
{
	char	model[64];	 	///< 厂商及型号,如"SAMSUNG HD103SI"
	char	sn[32];			///< 设备序列号，如"STH607MS2P8GAS"
	char	firmware[16];	///< 固件版本，如"ST6OA31E"
	int		reserved[36];	///< 保留空间
} StorageDetailInfo;


/// SMART 状态属性值, 64字节
typedef struct
{
	char*	name;			///< 属性名
	int		id;				///< ID
	int		current;		///< 属性值
	int		worst;			///< 最大出错值
	int		threshold;		///< 阈值
	char*	raw;			///< 实际值
	long	predict;		///< 状态
	int		reserved[9];	///< 保留位
} StorageSmartValue;


/// 存储设备卷类型
typedef enum StorageVolume
{
	storagePhysicalVolume = 0,	///< 物理硬盘，单盘
	storageRaidVolume = 1,		///< RAID磁盘阵列
	storageVolumeGroup = 2,		///< VG虚拟盘组
} StorageVolume;


/// 存储设备状态
typedef enum StorageState 
{
	storageRunning = 0x01,		///< 普通设备运行
	storageOffline = 0x02,		///< 普通设备离线
	storageActive = 0x04,		///< RAID设备活动
	storageSync = 0x08,			///< RAID设备同步
	storageSpare = 0x10,		///< RAID设备热备
	storageFaulty = 0x20,		///< RAID设备失效
	storageRebuilding = 0x40,	///< RAID设备重建
	storageRemoved = 0x80,		///< RAID设备移除
	storageAdding = 1 << 8,			///< 设备插入中，刚检测到设备插入，还没有创建设备节点
	storageAbortAdding = 1 << 9,	///< 设备移除中，还没有创建好设备节点的情况下，拔出设备
} StorageState;

/// 存储设备能力集
typedef enum StorageCaps
{
	storageCapsHotplug = 1,		///< 设备是否支持热插拔
} StorageCaps;

/// 存储设备信息结构, 32位系统下128字节
typedef struct StorageInfo
{
	char			name[32];	///< 设备名，"/dev/sda", "/dev/hda", "/dev/idea", "/dev/md0"
	char			media[16]; 	///< 介质类型，"CDROM", "DISK", "FLASH"...
	char			bus[16]; 	///< 总线类型，"SATA", "ESATA", "SCSI", "USB"...
	uint64			capacity;	///< 容量，字节为单位!
	int				port:8;		///< 同类设备存储接口的物理编号
	StorageVolume 	volume:8;	///< 存储设备卷类型
	uint32 			state:16;	///< 存储设备状态,StorageState的组合
	char			parent[32];	///< 本存储物理设备或者虚拟设备所在的上级存储组的名称，可能是VG或者RAID
	uint32			caps;		///< 存储设备能力集, StorageCaps 的组合
	int				reserved[4];///< 保留空间
} StorageInfo;

enum CheckStorageType
{
	checkStorageBreakDown	= 1 << 0,		///< 存储设备损坏
	checkStorageIOError		= 2 << 0,		///< 存储驱动异常
	checkStorageAll			= ~0,			///< 全部检测
};

/// 存储设备接口, 128个指针
typedef struct StorageDevice
{
	/// 底层私有数据
	void *priv;


	/// 增加接口引用
	int (*addRef)(struct StorageDevice *thiz);


	/// 释放接口
	int (*release)(struct StorageDevice *thiz);


	/// 加载存储设备
	///
	/// \param [in] thiz 本接口指针
	/// \retval 0  停止成功
	/// \retval <0  停止失败
	int (*load)(struct StorageDevice* thiz);


	/// 弹出存储设备
	///
	/// \param [in] thiz 本接口指针
	/// \retval 0  停止成功
	/// \retval <0  停止失败
	int (*eject)(struct StorageDevice* thiz);


	/// 设置存储设备休眠时间
	///
	/// \param [in] thiz 本接口指针
	/// \param [in] minutes 待命时间，分钟为单位
	/// \retval 0  休眠成功
	/// \retval <0  休眠失败
	int (*standby)(struct StorageDevice* thiz, int minutes);


	/// 唤醒存储设备。如果设备处于活动状态，也要执行唤醒命令，保证不会在超时后自动进入睡眠状态。
	///
	/// \param [in] thiz 本接口指针
	/// \retval 0  操作成功
	/// \retval <0  操作失败
	int (*wakeup)(struct StorageDevice* thiz);


	/// 得到设备的分区信息。
	///
	/// \param [in] thiz 本接口指针
	/// \param [out] list 用来存放分区信息的一个 PartitionInfo 数组。
	/// \param [in,out]  max 传入的值是数组的元素个数，传出的值是实际取到的个数。
	///        如果实际的分区数大于数组长度，则只取传入的长度。
	/// \retval 0  成功
	/// \retval <0  失败
	int (*getPartitionList)(struct StorageDevice* thiz, StoragePartitionInfo* list, int* max);


	/// 增加存储设备分区。
	///
	/// \param [in] thiz 本接口指针
	/// \param [in] part 分区名称，只对LVM有效
	/// \param [in] start 分区开始偏移，字节为单位
	/// \param [in] total 分区总大小，字节为单位
	/// \retval >=0  增加成功，返回此次增加的分区号
	/// \retval <0  失败
	int (*addPartition)(struct StorageDevice *thiz, char const* part, uint64 start, uint64 total);


	/// 删除存储设备分区。
	///
	/// \param [in] thiz 本接口指针
	/// \param [in] part 分区名称
	/// \retval 0  成功
	/// \retval <0  失败
	int (*deletePartition)(struct StorageDevice *thiz, char const* part);


	/// 格式化分区，只支持标准文件系统
	///
	/// \param [in] thiz 本接口指针
	/// \param [in] part 分区名称
	/// \param [in] fs文件系统类型，"FAT32"
	/// \retval 0  成功
	/// \retval <0  失败
	int (*formatPartition)(struct StorageDevice *thiz, char const* part, const char* fs);


	/// 设置分区格式，只有应用层文件系统TAEFS格式化时需要调用, 在格式化之前可将分区信息设置为""，格式化完成后设置为"TAEFS";
	///
	/// \param [in] thiz 本接口指针
	/// \param [in] part 分区名称
	/// \param [in] fs文件系统类型，"TAEFS", ""表示清空分区表中的分区类型，
	/// \retval 0 成功
	/// \retval <0 失败
	int (*setFormat)(struct StorageDevice *thiz, char const* part, const char *fs);


	/// 得到分区的可用空间字节数
	///
	/// \param [in] thiz 本接口指针
	/// \param [in] part 分区名称
	/// \param [out] freespace 存放返回可用字节数的指针
	/// \retval 0  成功
	/// \retval <0  失败
	int (*getFreeSpace)(struct StorageDevice *thiz, char const* part, uint64* freespace);


	/// 得到设备详细描述信息
	///
	/// \param [in] thiz 本接口指针
	/// \param [out] detail 存放返回详细信息的DeviceDetailInfo结构体指针
	/// \retval 0  成功
	/// \retval <0  失败
	int (*getDetailInfo)(struct StorageDevice *thiz, StorageDetailInfo* detail);


	/// 得到设备的SMART信息数组，只对物理盘有用。
	///
	/// \param [in] thiz 本接口指针
	/// \param [out] list 存放返回的SMART信息数组的首元素指针
	/// \retval >=0  成功, 返回实际的SMART信息数组的元素个数
	/// \retval <0  失败
	int (*getSmartValueList)(struct StorageDevice* thiz, StorageSmartValue** list);


	/// 释放SMART信息数组，只对物理盘有用
	///
	/// \param [in] thiz 本接口指针
	/// \param [in] list 要释放的SMART信息数组的首元素指针
	/// \retval 0  成功
	/// \retval <0  失败
	int (*freeSmartValueList)(struct StorageDevice* thiz, StorageSmartValue* list);


	/// 设置为热备盘，只对物理盘有用
	///
	/// \param [in] thiz 热备盘对应的Storage对象指针
	/// \param [in] enable 是否设置为热备盘, 1表示设置热备, 0表示清除热备，其他参数忽略
	/// \param [in] global 是否为全局热备, 1表示是, 0表示局部热备
	/// \param [in] name 如果global为1，则name为热备池的名称，否则表示RAID组的名称。
	/// \retval < 0 操作失败
	/// \retval 0 操作成功
	int (*setAsHotSpare)(struct StorageDevice *thiz, int enable, int global, const char *name);

	/// 复位存储设备
	/// 调用该接口时，需要先清理对该设备的操作资源，如卸载文件系统，
	/// \param [in] thiz 热备盘对应的Storage对象指针
	/// \retval < 0 操作失败
	/// \retval 0 操作成功
	int (*reset)(struct StorageDevice *thiz);

	/// 检测存储设备是否损坏
	///
	/// \param [in] thiz 热备盘对应的Storage对象指针
	/// \param [in] checkMask 指定检测出错类型掩码 参见CheckStorageType
	/// 调用该接口时，要求SD处于空闲状态，即不能进行读写操作
	/// \retval 0: 卡正常
	/// \retval -1: 操作失败
	/// \retval -2: 卡损坏
	/// \retval -3: sd卡驱动异常，需要强制复位恢复
	int (*checkStatus)(struct StorageDevice *thiz, int checkMask);

	/// 配置分区读写属性
	///
	/// \param [in] thiz 热备盘对应的Storage对象指针
	/// \param [in] part 分区名称
	/// \param [in] rw分区读写属性。0: 只读 1: 可读写
	/// 该接口只有分区为智诺文件系统时有效，否则执行失败
	/// \retval < 0 操作失败
	/// \retval 0 操作成功
	int (*setPartitionRw)(struct StorageDevice *thiz, char const *part, int rw);

	/// 获取分区读写属性
	///
	/// \param [in] thiz 热备盘对应的Storage对象指针
	/// \param [in] part 分区名称
	/// \param [out] rw分区读写属性。0: 只读 1: 可读写
	/// 该接口只有分区为智诺文件系统时有效，否则执行失败
	/// \retval < 0 操作失败
	/// \retval 0 操作成功
	int (*getPartitionRw)(struct StorageDevice *thiz, char const *part, int *rw);	
	
	int (*devMount)(struct StorageDevice *pThiz, char *devname, char *directory, char *type);

	int (*devUmount)(struct StorageDevice *pThiz, char *directory);
	
	/// 保留
	void* reserved[105];

} StorageDevice;


/// 存储总线信息结构, 128字节
typedef struct
{
	///< 总线的接口数目，包括扩展的总线。
	long	total;

	/// 已挂载的硬盘的数量, 不包括坏盘. 硬盘个数也等于mask中置1的位个数减去
	/// bad中置1的位个数. 应用程序访问硬盘时, 硬盘序号规则如下: 第一个被置1
	/// 的位对应的总线通道上挂载的正常硬盘的硬盘序号为0，第二个被置1的位对应正常
	/// 硬盘的硬盘序号为1，依次类推。
	long	plug;

	/// 指示各个总线通道上是否挂载硬盘，包括坏盘。每一位对应总线通道的主盘或从盘，
	/// 置位表示以挂载硬盘，否则没有。对应关系为bit0对应IDE0的主盘，bit1对应IDE0
	/// 的从盘，bit2对应IDE1的主盘，bit3对应IDE1的从盘，依次类推。
	unsigned long	mask;

	/// 指示各个通道上是否挂载了坏的硬盘。每一位对应通道的主盘或从盘，置位
	/// 表示以有坏硬盘，否则没有。对应关系同mask。
	unsigned long	bad;

	/// 保留
	long	reserved[28];

} StoragePorInfo;


/// 得到总线信息。
///
/// \param [in] bus 总线类型, "SATA", "ESATA", "SCSI", "USB"...
/// \param [out] info 用来存放返回的总线信息结构体指针。
/// \retval 0  成功
/// \retval <0  失败
int PAL_API getStoragePortInfo(const char* bus, StoragePorInfo* info);


/// 得到所有存储设备的信息；与最近一次调用时相比较，如果存储设备没有变更，函数一直阻塞。
/// 第一次调用时，如果之前已经有现成的信息，应立即返回现有信息。
/// 
/// \param [out] list 用来存放设备信息的一个BackupInfo数组。
/// \param [in,out]  max 传入的值是数组的元素个数，传出的值是实际取到的个数。
///        如果实际的设备数大于数组长度，则只取传入的长度。
/// \retval 0  成功
/// \retval <0  失败
int PAL_API getStorageList(StorageInfo* list, int *max);


/// 存储设备接口描述, 32位系统下128字节
typedef struct StorageDesc
{
	const char*  name;	///< 存储设备的名称。
	int reserved[31];	///< 保留
} StorageDesc;


/// 创建存储设备接口
///
/// \param [in] desc 存储设备接口描述结构 StorageDesc 指针
/// \param [out] storage 存储设备接口指针的指针
/// \retval <0 创建失败
/// \retval 0 创建成功
int PAL_API createStorage(StorageDesc *desc, StorageDevice** storage);


/// @} end of group

#ifdef __cplusplus
}
#endif

#endif //__STORAGE_API_H__

